package svc;

import constants.Constants;
import domain.BioRecord;
import domain.bw.BodyWeight;
import domain.cull.Cull;
import domain.milk.Milk;
import domain.misc.Misc;
import domain.price.Price;
import domain.repro.Repro;
import functions.Functions;

public class BioRecordSvc {
	
	public BioRecord getBioRecordDetails(int fileNo){
		System.out.println("Inside SVC ....");
		BioRecord bio = new BioRecord();
		
		MiscSvc miscSvc = new MiscSvc();
		MilkSvc milkSvc = new MilkSvc();
		CullSvc cullSvc = new CullSvc();
		ReproSvc reproSvc = new ReproSvc();
		BWSvc bwSvc = new BWSvc();
		PriceSvc priceSvc = new PriceSvc();
		
		
		Misc misc = miscSvc.getMiscDetails(fileNo);
		//Milk milk = milkSvc.getMilkDetails(fileNo, misc.getUnit());
		Milk milk = milkSvc.getMilkDetails(fileNo);
		Cull cull = cullSvc.getCullDetails(fileNo);
		Repro repro = reproSvc.getReproDetails(fileNo);
		//BodyWeight bw = bwSvc.getBodyWeightDetails(fileNo, misc.getUnit());
		BodyWeight bw = bwSvc.getBodyWeightDetails(fileNo);
		Price price = priceSvc.getPriceDetails(fileNo);
		
		
		bio.setMilk_mpreg(milk.getMilkYieldPreg());
		double mlk[][][] = milk.getMilk();
		
		double odds[] = cull.getCullRiskLact();
		double pind[][] = cull.getPind();
		
		bio.setAbort(repro.getAbortRisk());
		bio.setVwp(repro.getMisc().getVwp());
		bio.setLbm(repro.getMisc().getLbm());
		bio.setTimebreeding(repro.getMisc().getTimeBreeding());
		bio.setP_semen(repro.getMisc().getP_semen());
		bio.setMaxlact(repro.getMisc().getMaxLact());
		double concrisk[] = repro.getConcRisk();
		
		bio.setHeatdetectionrate(repro.getHeatDetectionRate());
		bio.setConceptionrate(repro.getConceptionRate());
		// Repro COST      -- bio.setReprocost(repro.get)
		
		bio.setBw(bw.getBwOpen());
		bio.setBwpreg(bw.getBwPreg());
		
		int serve[] = price.getServe();
		int enter[] = price.getEnter();
		
		double p_heifer[] = price.getP_heifer();
		double p_milk[] = price.getP_milk();
		double p_bodyweight[] = price.getP_bodyweight();
		
		
		//bio.setUnit(misc.getUnit());
		bio.setUnit(1);								// For calculation purpose we will always have unit as KG
		bio.setAnalysis(misc.getAnalysis());
		bio.setWritepol(misc.getWritepol());
		bio.setWriterpo(misc.getWriterpo());
		bio.setStart_sea(misc.getStart_sea());		//startSeason = "JAN";
		bio.setPolicy(misc.getPolicy());			//policy = "OPTIMAL";
		bio.setMaxmim(misc.getMaxmim());
		bio.setCullmilk(misc.getCullmilk());
		bio.setCullmargin(misc.getCullmargin());
		bio.setInterest(misc.getInterest());
		bio.setP_loss(misc.getP_loss());
		bio.setInvcullpct(misc.getInvcullpct());
		bio.setFunk(misc.getFunk());
		bio.setP_calf(misc.getP_calf());
		bio.setP_fixed_labor(misc.getP_fixed_labor());
		bio.setP_fixed_other(misc.getP_fixed_other());
		bio.setP_other_dry(misc.getP_other_dry());
		bio.setP_other_lact(misc.getP_other_lact());
		bio.setP_tmrdmlac(misc.getP_tmrdmlac());
		bio.setP_tmrdmdry(misc.getP_tmrdmdry());
		bio.setDmi_dry(misc.getDmi_dry());
		bio.setPctfat(misc.getPctfat());
		bio.setPa_cv(misc.getPa_cv());
		bio.setMilkrepeat(misc.getMilkrepeat());
		bio.setP_labor(misc.getP_labor());
		bio.setTimefresh(misc.getTimefresh());
		bio.setTimelact(misc.getTimelact());
		bio.setTimedry(misc.getTimedry());
		bio.setVetcost(misc.getVetcost());
		
		double milk4[] = milk.getMilkYieldLact();
		
		
		bio = updateBioRecordDetails(bio, mlk, odds, pind, concrisk, serve, enter, p_heifer, p_milk, p_bodyweight, milk4);
		
		return bio;
	}
	
	

	@SuppressWarnings("unused")
	public static BioRecord updateBioRecordDetails(BioRecord bio, double mlk[][][], double odds[],
			double pind[][], double concrisk[], int serve[], int enter[], 
			double p_heifer[], double p_milk[], double p_bodyweight[], 
			/*String startSeason, String policy, */double milk4[]){
		
		bio.getVwp()[1] = bio.getVwp()[1] - 1;
		bio.getVwp()[2] = bio.getVwp()[2] - 1;
		bio.getVwp()[3] = bio.getVwp()[3] - 1;
		bio.setLbm(bio.getLbm() - 1);
		
		
		for(int i = 1; i <= 2; i++)	
			for(int mpreg = 1; mpreg <= Constants.MPREG; mpreg++)
			{
				for(int mim = 1; mim <= Constants.MIM; mim++)
				{
					if(i == 1) bio.getBw()[1][mim][mpreg] = bio.getBw()[1][mim][0] + bio.getBwpreg()[i][mpreg];

					if(i == 2) 
						for(int lact = 2; lact <= Constants.LACT; lact++)
							bio.getBw()[lact][mim][mpreg] = bio.getBw()[2][mim][0] + bio.getBwpreg()[i][mpreg];


				}
			}
		
		/*
		if(startSeason.equalsIgnoreCase("JAN")) bio.setStart_sea(1);
		if(startSeason.equalsIgnoreCase("FEB")) bio.setStart_sea(2);
		if(startSeason.equalsIgnoreCase("MAR")) bio.setStart_sea(3);
		if(startSeason.equalsIgnoreCase("APR")) bio.setStart_sea(4);
		if(startSeason.equalsIgnoreCase("MAY")) bio.setStart_sea(5);
		if(startSeason.equalsIgnoreCase("JUN")) bio.setStart_sea(6);
		if(startSeason.equalsIgnoreCase("JUL")) bio.setStart_sea(7);
		if(startSeason.equalsIgnoreCase("AUG")) bio.setStart_sea(8);
		if(startSeason.equalsIgnoreCase("SEP")) bio.setStart_sea(9);
		if(startSeason.equalsIgnoreCase("OCT")) bio.setStart_sea(10);
		if(startSeason.equalsIgnoreCase("NOV")) bio.setStart_sea(11);
		if(startSeason.equalsIgnoreCase("DEC")) bio.setStart_sea(12);
		
		
		
		if(policy.equalsIgnoreCase("OPTIMAL")) bio.setPolicy(1);
		if(policy.equalsIgnoreCase("KEEPPREG")) bio.setPolicy(2);
		if(policy.equalsIgnoreCase("KEEPALL")) bio.setPolicy(3);
		if(policy.equalsIgnoreCase("USE_POL")) bio.setPolicy(0);
		*/
		
		if(bio.getMaxmim() <= bio.getLbm()) bio.setMaxmim(Constants.MIM); 
		
		
		//prices
		for(int i = 1; i <= 24; i++)
		{
			int sea = bio.getStart_sea() + i - 1;
			if(i <= 12) while(sea > Constants.SEA) sea = sea - Constants.SEA;
			else while(sea > Constants.SEA*2) sea = sea - Constants.SEA;
			bio.getServe()[sea] = serve[i];
			bio.getEnter()[sea] = enter[i];
			bio.getP_heifer()[sea] = p_heifer[i];
			bio.getP_milk()[sea] = p_milk[i];
			bio.getP_bodyweight()[sea] = p_bodyweight[i];
		}

		//milk
		//Van Arendonk has very little variation around low producing cows (10%): if milk yield is low, so is the
		//curr = 1 to 15 variation.  Instead we could have a constant variation, independent of mim.
		for(int lact = 1; lact <= 3; lact++)
			for(int mim = 1; mim <= 10; mim++)
				for(int sea = 1; sea <= Constants.SEA; sea++)
					mlk[lact][0][0] += mlk[lact][mim][sea] / (10 * Constants.SEA);	//average daily yield per lactation
	//	for(lact = 1; lact <= 3; lact++) printf("\n %d %.2f",lact, mlk[lact][0][0]); stop(0);

		bio.getMilk_mpreg()[0] = 1.0;
		
		/***
		 * bio_smy();											//calculate bio.getsmy[curr] using pa_cv
		 */
		
		Functions fun = new Functions();
		bio = fun.bio_smy(bio);
		
		double milk = 0;
		double avg = 0;
		double fcm = 0;
		double dmi = 0;
		double labor = 0;
		
		
		
		for(int sea = 1; sea <= 24; sea++)
			bio.getP_milk()[sea] = bio.getP_milk()[sea] / 100;		//price per kg milk
		for(int lact = 1; lact <= Constants.LACT; lact++)
			for(int mim = 1; mim <= Constants.MIM; mim++)
				for(int mpreg = 0; mpreg <= Constants.MPREG; mpreg++)
					for(int sea = 1; sea <= Constants.SEA; sea++)
					{
						if(lact == 1) { milk = mlk[1][mim][sea]; avg = mlk[1][0][0]; }
						if(lact == 2) { milk = mlk[2][mim][sea]; avg = mlk[2][0][0]; }
						if(lact == 3) { milk = mlk[3][mim][sea]; avg = mlk[3][0][0]; }
						if(lact >= 4) { milk = mlk[3][mim][sea] * milk4[lact]; avg = mlk[3][0][0] * milk4[lact]; }
						milk = milk * bio.getMilk_mpreg()[mpreg];				//pregnancy reduction
						for(int curr = 1; curr <= Constants.CURR; curr++)
						{
							bio.getMilkyield()[curr][lact][mim][mpreg][sea] = (bio.getSmy()[curr] / 100 * milk) * Constants.STAGE;

						//	bio.getMilkyield()[curr][lact][mim][mpreg][sea] = (milk + (bio.getsmy[curr]-100)/100 * avg); //* Constants.STAGE;
							if(bio.getMilkyield()[curr][lact][mim][mpreg][sea] < 0.0) bio.getMilkyield()[curr][lact][mim][mpreg][sea] = 0.0;

//if(lact == 1 && mim == 1) bio.getMilkyield()[curr][lact][mim][mpreg][sea] = 0.0;

							bio.getRev()[curr][lact][mim][mpreg][sea] = bio.getP_milk()[sea] * bio.getMilkyield()[curr][lact][mim][mpreg][sea];
							bio.getRev()[curr][lact][mim][mpreg][sea+12] = bio.getP_milk()[sea+12] * bio.getMilkyield()[curr][lact][mim][mpreg][sea];
							bio.getIofc()[curr][lact][mim][mpreg][sea] = bio.getRev()[curr][lact][mim][mpreg][sea];
							bio.getIofc()[curr][lact][mim][mpreg][sea+12] = bio.getRev()[curr][lact][mim][mpreg][sea+12];


						
						}
					}



		//(involuntary) culling
		for(int lact = 1; lact <= Constants.LACT; lact++)
		{
			for(int mim = 1; mim <= Constants.MIM; mim++)
				for(int sea = 1; sea <= Constants.SEA; sea++)
				{
					bio.getPind()[lact][mim][sea] 
						= pind[mim][sea] * odds[lact];
					if(bio.getPind()[lact][mim][sea] > 1) bio.getPind()[lact][mim][sea] = 1.0;
		//				= 0.02;
				
		//			if(sea == 1) printf("\nlact:%d mim:%d %.3lf",lact,mim,bio.getpind[lact][mim][sea]);
		//			else printf(" %.3lf",bio.getpind[lact][mim][sea]);
				}
		//	stop(0);
		}

		//reproduction
		for(int mim = 2; mim <= 15; mim++)
			for(int sea = 1; sea <= Constants.SEA; sea++)
				for(int lact = 1; lact <= Constants.LACT; lact++)
				{

			//	printf(" %.2f ",bio.getconceptionrate[0][2][1]);

			//	printf(" %2d %2d %2d %.2f ",mim,sea,lact,bio.getconceptionrate[0][mim][sea]);

					bio.getConceptionrate()[lact][mim][sea] = concrisk[lact] * bio.getConceptionrate()[0][mim][sea];
					if(bio.getConceptionrate()[lact][mim][sea] > 1.0) bio.getConceptionrate()[lact][mim][sea] = 1.0;
					
				//	printf("mim:%d sea:%d lact:%d  %f x concrisk:%f = %f",mim,sea,lact,bio.getconceptionrate[0][mim][sea],concrisk[lact],bio.getconceptionrate[lact][mim][sea]);
				//	stop(0);
				}


		//body weight
		for(int lact = 1; lact <= Constants.LACT; lact++)
			for(int mim = 1; mim <= Constants.MIM; mim++)
				for(int sea = 1; sea <= Constants.SEA; sea++)
				{
					if(lact >= 3) for(int mpreg = 0; mpreg <= Constants.MPREG; mpreg++) bio.getBw()[lact][mim][mpreg] = bio.getBw()[2][mim][mpreg];
					bio.getSel()[lact][mim][sea] = bio.getBw()[lact][mim][0] * bio.getP_bodyweight()[sea];
					bio.getSel()[lact][mim][sea+12] = bio.getBw()[lact][mim][0] * bio.getP_bodyweight()[sea+12];


				}
		//stop(0);
		//dry matter intake
		//other cost
		for(int curr = 1; curr <= Constants.CURR; curr++)
			for(int lact = 1; lact <= Constants.LACT; lact++)
				for(int mim = 1; mim <= Constants.MIM; mim++)
					for(int sea = 1; sea <= Constants.SEA; sea++)
						for(int mpreg = 0; mpreg <= Constants.MPREG; mpreg++)
						{


							if(bio.getMilkyield()[curr][lact][mim][mpreg][sea] > 0.01)		//cow is lactating
							{	//NRC[1112]4
								if(bio.getUnit() == 1)					//milk and bw entered as kg
								{
									fcm = 0.4 * bio.getMilkyield()[curr][lact][mim][mpreg][sea] / Constants.STAGE
										+ 0.15 * bio.getPctfat() * bio.getMilkyield()[curr][lact][mim][mpreg][sea] / Constants.STAGE;	//fat correct milk per day
									dmi = 0.372 * fcm + 0.0968 * Math.pow(bio.getBw()[lact][mim][mpreg],0.75) * (1 - Math.exp(- 0.192 * (((double)(mim-1)*4.34+2.17) + 3.67)));
									dmi = dmi * Constants.STAGE;
								}
								else if(bio.getUnit() == 0)				//milk and bw entered as lbs
								{									//calculations must happen with kg
									fcm = 0.4 * bio.getMilkyield()[curr][lact][mim][mpreg][sea] / Constants.STAGE
										+ 0.15 * bio.getPctfat() * bio.getMilkyield()[curr][lact][mim][mpreg][sea] / Constants.STAGE;	//fat correct milk per day
									dmi = 0.372 * (fcm/2.204624) + 0.0968 * Math.pow((bio.getBw()[lact][mim][mpreg]/2.204624),0.75) * (1 - Math.exp(- 0.192 * (((double)(mim-1)*4.34+2.17) + 3.67)));
									dmi = dmi * 2.204624 * Constants.STAGE;	//dmi as lbs
								}
/*								else
								{ printf("\n READ_BIO_FILE dmi error"); stop(0); }
*/								
								bio.getRev()[curr][lact][mim][mpreg][sea] -= dmi * bio.getP_tmrdmlac();
								bio.getRev()[curr][lact][mim][mpreg][sea] -= bio.getP_other_lact() * Constants.STAGE;
								bio.getRev()[curr][lact][mim][mpreg][sea+12] -= dmi * bio.getP_tmrdmlac();
								bio.getRev()[curr][lact][mim][mpreg][sea+12] -= bio.getP_other_lact() * Constants.STAGE;

								bio.getIofc()[curr][lact][mim][mpreg][sea] -= dmi * bio.getP_tmrdmlac();
								bio.getIofc()[curr][lact][mim][mpreg][sea] -= bio.getP_other_lact() * Constants.STAGE;
								bio.getIofc()[curr][lact][mim][mpreg][sea+12] -= dmi * bio.getP_tmrdmlac();
								bio.getIofc()[curr][lact][mim][mpreg][sea+12] -= bio.getP_other_lact() * Constants.STAGE;

								bio.getVarcost()[curr][lact][mim][mpreg][sea] += dmi * bio.getP_tmrdmlac();
								bio.getVarcost()[curr][lact][mim][mpreg][sea] += bio.getP_other_lact() * Constants.STAGE;
								bio.getVarcost()[curr][lact][mim][mpreg][sea+12] += dmi * bio.getP_tmrdmlac();
								bio.getVarcost()[curr][lact][mim][mpreg][sea+12] += bio.getP_other_lact() * Constants.STAGE;

							}
							if(bio.getMilkyield()[curr][lact][mim][mpreg][sea] < 0.01)		//cow is dry
							{
								dmi = bio.getDmi_dry() * Constants.STAGE;		//only maintenance
								bio.getRev()[curr][lact][mim][mpreg][sea] -= dmi * bio.getP_tmrdmdry();
								bio.getRev()[curr][lact][mim][mpreg][sea] -= bio.getP_other_dry() * Constants.STAGE;
								bio.getRev()[curr][lact][mim][mpreg][sea+12] -= dmi * bio.getP_tmrdmdry();
								bio.getRev()[curr][lact][mim][mpreg][sea+12] -= bio.getP_other_dry() * Constants.STAGE;

								bio.getIofc()[curr][lact][mim][mpreg][sea] -= dmi * bio.getP_tmrdmlac();
								bio.getIofc()[curr][lact][mim][mpreg][sea] -= bio.getP_other_lact() * Constants.STAGE;
								bio.getIofc()[curr][lact][mim][mpreg][sea+12] -= dmi * bio.getP_tmrdmlac();
								bio.getIofc()[curr][lact][mim][mpreg][sea+12] -= bio.getP_other_lact() * Constants.STAGE;

								bio.getVarcost()[curr][lact][mim][mpreg][sea] += dmi * bio.getP_tmrdmlac();
								bio.getVarcost()[curr][lact][mim][mpreg][sea] += bio.getP_other_lact() * Constants.STAGE;
								bio.getVarcost()[curr][lact][mim][mpreg][sea+12] += dmi * bio.getP_tmrdmlac();
								bio.getVarcost()[curr][lact][mim][mpreg][sea+12] += bio.getP_other_lact() * Constants.STAGE;

							}
							bio.getDmi()[curr][lact][mim][mpreg][sea]  = dmi;
					


						}
		//veterinary cost
		for(int mim = 1; mim <= Constants.MIM; mim++)
		{
			if(mim <= 4) bio.getVetcost()[mim] = bio.getVetcost()[mim];
			else bio.getVetcost()[mim] = bio.getVetcost()[4];
		}
		//labor cost (rev[] does not include reproductive labor)
		//labor minutes
		//veterinary cost
		for(int curr = 1; curr <= Constants.CURR; curr++)
			for(int lact = 1; lact <= Constants.LACT; lact++)
				for(int mim = 1; mim <= Constants.MIM; mim++)
					for(int sea = 1; sea <= Constants.SEA; sea++)
						for(int mpreg = 0; mpreg <= Constants.MPREG; mpreg++)
						{
							if(bio.getMilkyield()[curr][lact][mim][mpreg][sea] >= 0.01) labor = bio.getTimelact();	//lactating cow (minutes/month)
							if(bio.getMilkyield()[curr][lact][mim][mpreg][sea]  < 0.01) labor = bio.getTimedry();	//dry cow (minutes/month)
							if(mim == 1) labor += bio.getTimefresh();	//fresh cow (minutes/month)
							bio.getTimecows()[curr][lact][mim][mpreg][sea] = labor;
							
							bio.getRev()[curr][lact][mim][mpreg][sea] -= bio.getTimecows()[curr][lact][mim][mpreg][sea] / 60 * bio.getP_labor();
							bio.getRev()[curr][lact][mim][mpreg][sea] -= bio.getVetcost()[mim];
							bio.getRev()[curr][lact][mim][mpreg][sea+12] -= bio.getTimecows()[curr][lact][mim][mpreg][sea] / 60 * bio.getP_labor();
							bio.getRev()[curr][lact][mim][mpreg][sea+12] -= bio.getVetcost()[mim];

							bio.getVarcost()[curr][lact][mim][mpreg][sea] += bio.getTimecows()[curr][lact][mim][mpreg][sea] / 60 * bio.getP_labor();
							bio.getVarcost()[curr][lact][mim][mpreg][sea] += bio.getVetcost()[mim];
							bio.getVarcost()[curr][lact][mim][mpreg][sea+12] += bio.getTimecows()[curr][lact][mim][mpreg][sea] / 60 * bio.getP_labor();
							bio.getVarcost()[curr][lact][mim][mpreg][sea+12] += bio.getVetcost()[mim];


						}
					//	stop(0);
	
		
		return bio;
	}


}
